import { useContext, useState, useRef, RefObject, useEffect } from 'react'
import { PlusOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons'
import { Dropdown, Button, Menu, message } from 'antd'
import style from './index.module.less'
import { CaseContext } from '../../context'
import { OperateSchema } from '@src/components/schema/operate'
import Tab, { TabSchema } from './tab'
import { delOperateRequest, getOperateRequest, addOperateRequest } from './ajax'
import { awaitWrap } from '@src/assets/js/tool'
import { useDispatch } from 'react-redux'
import { addResizeEvent, delResizeEvent } from '@src/redux/actions/globalEvent'
import { getOperateComponent } from '../Operates/operateModules'
import LazyLoad from '@src/components/lazyLoader/index'

async function getOperateList (
  operate: string,
  caseid: string,
  activeKey: string,
  usedOperate: OperateSchema[],
  unuseOperate: OperateSchema[],
  tabContainerRef: RefObject<HTMLDivElement>,
  tabsRef: RefObject<HTMLDivElement>,
  activeTabRef: RefObject<TabSchema>,
  scrollLeft: number,
  openedOperateKey: string[],
  setIsOver: (v: boolean) => void,
  setScrollLeft: (v: number) => void,
  setActiveKey: (v: string) => void,
  setOpenedOperateKey: (v: string[]) => void,
  setUseOperate: (v: OperateSchema[]) => void,
  setUnuseOperate: (v: OperateSchema[]) => void
) {
  const [e, d] = await awaitWrap(getOperateRequest(caseid))
  if (e === null && d !== null) {
    const { used, unuse } = d
    const usedKeys = used.map(li => li.key)
    const unuseKeys = unuse.map(li => li.key)
    activeKey = activeKey || operate
    const keyInUsedIndex = usedKeys.indexOf(activeKey)
    const keyInUnuseIndex = unuseKeys.indexOf(activeKey)
    if (activeKey) {
      if (keyInUsedIndex === -1 && keyInUnuseIndex !== -1) {
        used.push(unuse[keyInUnuseIndex])
        unuse.splice(keyInUnuseIndex, 1)
      } else if (keyInUsedIndex === -1 && keyInUnuseIndex === -1) {
        activeKey = ''
      }
    } else {
      if (used.length) {
        activeKey = used[0].key
      } else if (unuse.length) {
        used.push(unuse[0])
        activeKey = unuse[0].key
        unuse.shift()
      } else {
        activeKey = ''
      }
    }
    setUseOperate(used)
    setUnuseOperate(unuse)
    setActiveKey(activeKey)
    setOpenedOperateKey(activeKey ? [activeKey] : [])
    initActiveKey(operate, caseid, usedOperate, unuseOperate, tabContainerRef, tabsRef, activeTabRef, scrollLeft, openedOperateKey, setIsOver, setScrollLeft, setActiveKey, setOpenedOperateKey, setUseOperate, setUnuseOperate)
  }
}

// 初始化选中项
function initActiveKey (
  operate: string,
  caseid: string,
  usedOperate: OperateSchema[],
  unuseOperate: OperateSchema[],
  tabContainerRef: RefObject<HTMLDivElement>,
  tabsRef: RefObject<HTMLDivElement>,
  activeTabRef: RefObject<TabSchema>,
  scrollLeft: number,
  openedOperateKey: string[],
  setIsOver: (v: boolean) => void,
  setScrollLeft: (v: number) => void,
  setActiveKey: (v: string) => void,
  setOpenedOperateKey: (v: string[]) => void,
  setUseOperate: (v: OperateSchema[]) => void,
  setUnuseOperate: (v: OperateSchema[]) => void
) {
  if (!operate) {
    return initLayout(tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft)
  }
  const isUsed = usedOperate.find(li => li.key === operate) !== undefined
  const isUnUsed = unuseOperate.find(li => li.key === operate) !== undefined
  if (isUsed) {
    selectActiveKey(operate, usedOperate, unuseOperate, openedOperateKey, tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft, setActiveKey, setOpenedOperateKey, setUseOperate, setUnuseOperate)
  } else if (isUnUsed) {
    openTag({ key: operate }, caseid, usedOperate, unuseOperate, openedOperateKey, tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft, setActiveKey, setOpenedOperateKey, setUseOperate, setUnuseOperate)
  }
}

// 打开标签
function openTag (
  operate: { key: string },
  caseid: string,
  usedOperate: OperateSchema[],
  unuseOperate: OperateSchema[],
  openedOperateKey: string[],
  tabContainerRef: RefObject<HTMLDivElement>,
  tabsRef: RefObject<HTMLDivElement>,
  activeTabRef: RefObject<TabSchema>,
  scrollLeft: number,
  setIsOver: (v: boolean) => void,
  setScrollLeft: (v: number) => void,
  setActiveKey: (v: string) => void,
  setOpenedOperateKey: (v: string[]) => void,
  setUseOperate: (v: OperateSchema[]) => void,
  setUnuseOperate: (v: OperateSchema[]) => void
) {
  usedOperate = usedOperate.slice()
  unuseOperate = unuseOperate.slice()
  const index = unuseOperate.map(li => li.key).indexOf(operate.key)
  if (index === -1) {
    return false
  }
  usedOperate.push(unuseOperate[index])
  unuseOperate.splice(index, 1)
  setUnuseOperate(unuseOperate)
  setUseOperate(usedOperate)
  setActiveKey(operate.key)
  setOpenedOperateKey(getNewOpened(operate.key, openedOperateKey))
  initLayout(tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft)
  openOperateRequest(caseid, operate.key)
}

// 记录新增的操作
async function openOperateRequest (caseid: string, operate: string) {
  await awaitWrap(addOperateRequest(caseid, operate))
}

function leftClickHandle (
  tabContainerRef: RefObject<HTMLDivElement>,
  tabsRef:RefObject<HTMLDivElement>,
  scrollLeft: number,
  isOver: boolean,
  setScrollLeft: (v: number) => void
) {
  const tabContainer = tabContainerRef.current
  const tabs = tabsRef.current
  if (!tabContainer || !tabs) {
    return setTimeout(() => {
      leftClickHandle(tabContainerRef, tabsRef, scrollLeft, isOver, setScrollLeft)
    }, 100)
  }
  const containerWidth = isOver ? tabContainer.offsetWidth - 64 : tabContainer.offsetWidth
  if (scrollLeft + containerWidth < 0) {
    scrollLeft = scrollLeft + containerWidth
  } else {
    scrollLeft = 0
  }
  setScrollLeft(scrollLeft)
}

function rightClickHandle (
  tabContainerRef: RefObject<HTMLDivElement>,
  tabsRef:RefObject<HTMLDivElement>,
  scrollLeft: number,
  isOver: boolean,
  setScrollLeft: (v: number) => void
) {
  const tabContainer = tabContainerRef.current
  const tabs = tabsRef.current
  if (!tabContainer || !tabs) {
    return setTimeout(() => {
      rightClickHandle(tabContainerRef, tabsRef, scrollLeft, isOver, setScrollLeft)
    }, 100)
  }
  const containerWidth = isOver ? tabContainer.offsetWidth - 64 : tabContainer.offsetWidth
  const tabsWidth = tabs.offsetWidth
  if (scrollLeft + tabsWidth - containerWidth > containerWidth) {
    scrollLeft = scrollLeft - containerWidth
  } else {
    scrollLeft = containerWidth - tabsWidth
  }
  setScrollLeft(scrollLeft)
}

// 格式化布局
function initLayout (
  tabContainerRef: RefObject<HTMLDivElement>,
  tabsRef: RefObject<HTMLDivElement>,
  activeTabRef: RefObject<TabSchema>,
  scrollLeft: number,
  setIsOver: (v: boolean) => void,
  setScrollLeft: (v: number) => void
) {
  const tabContainer = tabContainerRef.current
  const tabs = tabsRef.current
  if (!tabContainer || !tabs || !activeTabRef.current) {
    return setTimeout(() => {
      initLayout(tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft)
    }, 100)
  }
  let activeTab = activeTabRef.current.tabRef.current
  let containerWidth = tabContainer.offsetWidth
  const listWidth = tabs.offsetWidth
  const isOver = listWidth > containerWidth
  const activeLeft = activeTab?.offsetLeft || 0
  const activeWidth = activeTab?.offsetWidth || 0
  if (isOver) {
    containerWidth = containerWidth - 64
  }
  if (scrollLeft + activeLeft < 0) {
    scrollLeft = -activeLeft
  } else if (scrollLeft + activeLeft + activeWidth > containerWidth) {
    scrollLeft = containerWidth - (activeLeft + activeWidth)
  }
  if (listWidth < containerWidth) {
    scrollLeft = 0
  } else if (scrollLeft + listWidth < containerWidth) {
    scrollLeft = containerWidth - listWidth
  } else if (scrollLeft > 0) {
    scrollLeft = 0
  }
  setIsOver(isOver)
  setScrollLeft(scrollLeft)
}

// 渲染下拉按钮
function renderDropdown (
  caseid: string,
  usedOperate: OperateSchema[],
  unuseOperate: OperateSchema[],
  openedOperateKey: string[],
  tabContainerRef: RefObject<HTMLDivElement>,
  tabsRef: RefObject<HTMLDivElement>,
  activeTabRef: RefObject<TabSchema>,
  scrollLeft: number,
  setIsOver: (v: boolean) => void,
  setScrollLeft: (v: number) => void,
  setActiveKey: (v: string) => void,
  setOpenedOperateKey: (v: string[]) => void,
  setUseOperate: (v: OperateSchema[]) => void,
  setUnuseOperate: (v: OperateSchema[]) => void
) {
  const items = unuseOperate.map(li => {
    return {
      label: li.title,
      key: li.key
    }
  })
  return (
    <Dropdown overlay={(
      <Menu className={style['menu-block']} items={items} onClick={(k) => openTag(k, caseid, usedOperate, unuseOperate, openedOperateKey, tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft, setActiveKey, setOpenedOperateKey, setUseOperate, setUnuseOperate)} />
    )} trigger={['click']}>
      <Button type='link' icon={<PlusOutlined />}>添加操作</Button>
    </Dropdown>
  )
}

// 设置当前操作的模块
function selectActiveKey (
  key: string,
  usedOperate: OperateSchema[],
  unuseOperate: OperateSchema[],
  openedOperateKey: string[],
  tabContainerRef: RefObject<HTMLDivElement>,
  tabsRef: RefObject<HTMLDivElement>,
  activeTabRef: RefObject<TabSchema>,
  scrollLeft: number,
  setIsOver: (v: boolean) => void,
  setScrollLeft: (v: number) => void,
  setActiveKey: (v: string) => void,
  setOpenedOperateKey: (v: string[]) => void,
  setUseOperate: (v: OperateSchema[]) => void,
  setUnuseOperate: (v: OperateSchema[]) => void
) {
  usedOperate = usedOperate.slice()
  unuseOperate = unuseOperate.slice()
  const unuseIndex = unuseOperate.map(li => li.key).indexOf(key)
  openedOperateKey = getNewOpened(key, openedOperateKey)

  setActiveKey(key)
  setOpenedOperateKey(openedOperateKey)
  initLayout(tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft)

  if (unuseIndex !== -1) {
    usedOperate.push(unuseOperate[unuseIndex])
    unuseOperate.splice(unuseIndex, 1)
    setUseOperate(usedOperate)
    setUnuseOperate(unuseOperate)
    initLayout(tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft)
  }
}

// 获取新的已打开操作
function getNewOpened (
  key: string,
  openedOperateKey: string[]
) {
  openedOperateKey = openedOperateKey.slice()
  const index = openedOperateKey.indexOf(key)
  if (index === -1) {
    openedOperateKey.push(key)
  }
  return openedOperateKey
}

// 清除操作
async function closeOperateRequest (caseid: string, operate: string) {
  await awaitWrap(delOperateRequest(caseid, operate))
}


function closeTagHandle (
  i: number,
  caseid: string,
  usedOperate: OperateSchema[],
  unuseOperate: OperateSchema[],
  activeKey: string,
  openedOperateKey: string[],
  tabContainerRef: RefObject<HTMLDivElement>,
  tabsRef: RefObject<HTMLDivElement>,
  activeTabRef: RefObject<TabSchema>,
  scrollLeft: number,
  setIsOver: (v: boolean) => void,
  setScrollLeft: (v: number) => void,
  setActiveKey: (v: string) => void,
  setOpenedOperateKey: (v: string[]) => void,
  setUseOperate: (v: OperateSchema[]) => void,
  setUnuseOperate: (v: OperateSchema[]) => void
) {
  usedOperate = usedOperate.slice()
  unuseOperate = unuseOperate.slice()
  const usedKeys = usedOperate.map(li => li.key)
  closeOperateRequest(caseid, usedOperate[i].key)
  const len = usedOperate.length
  let key = activeKey
  if (activeKey === usedKeys[i]) {
    if (i === len - 1) {
      if (len > 1) {
        key = usedKeys[i - 1]
      } else {
        key = ''
      }
    } else if (i === 0) {
      key = usedKeys[1]
    } else {
      key = usedKeys[i - 1]
    }
  }
  const list = usedOperate.splice(i, 1)
  unuseOperate = unuseOperate.concat(list)
  openedOperateKey = getNewOpened(key, openedOperateKey)
  setUseOperate(usedOperate)
  setUnuseOperate(unuseOperate)
  setActiveKey(key)
  setOpenedOperateKey(openedOperateKey)
  initLayout(tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft)
}

// 渲染标签内容
function renderContent (usedOperate: OperateSchema[], activeKey: string, openedOperateKey: string[]) {
  return (
    <div className={style.content}>
      {
        usedOperate.map(li => {
          const loadFn = getOperateComponent(li)
          const s = [style['tab-pane']]
          if (li.key !== activeKey) {
            s.push(style.hide)
          }
          return (
            <div className={s.join(' ')} key={li.key}>
              {loadFn ? renderPane(li, loadFn, openedOperateKey) : <span>模块不存在</span>}
            </div>
          )
        })
      }
    </div>
  )
}

// 渲染操作页
function renderPane (li: OperateSchema, loadFn: () => Promise<{ default: any }>, openedOperateKey: string[]) {
  const unopened = openedOperateKey.indexOf(li.key) === -1
  if (unopened) {
    return null
  }
  return (
    <LazyLoad loadFn={loadFn} props={{}} />
  )
}

function Main () {
  const c = useContext(CaseContext)
  const [isOver, setIsOver] = useState(false)
  const [scrollLeft, setScrollLeft] = useState(0)
  const [unuseOperate, setUnuseOperate] = useState<OperateSchema[]>([])
  const [usedOperate, setUseOperate] = useState<OperateSchema[]>([])
  const [activeKey, setActiveKey] = useState<string>('')
  const [openedOperateKey, setOpenedOperateKey] = useState<string[]>([])
  const tabContainerRef = useRef<HTMLDivElement>(null)
  const tabsRef = useRef<HTMLDivElement>(null)
  const activeTabRef = useRef<TabSchema>(null)
  const dispatch = useDispatch()
  const tabContainerClass = [style['tab-container']]
  const prevClass = [style['tab-btn'], style.prev]
  const nextClass = [style['tab-btn'], style.next]
  if (isOver) {
    tabContainerClass.push(style.over)
  } else {
    prevClass.push(style.hide)
    nextClass.push(style.hide)
  }
  useEffect(() => {
    getOperateList(c.operate, c.caseid, activeKey, usedOperate, unuseOperate, tabContainerRef, tabsRef, activeTabRef, scrollLeft, openedOperateKey, setIsOver, setScrollLeft, setActiveKey, setOpenedOperateKey, setUseOperate, setUnuseOperate)
    dispatch(addResizeEvent({
      name: `${c.caseid}-operate-tab`,
      handle: () => initLayout(tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft)
    }))
    return () => {
      dispatch(delResizeEvent(`${c.caseid}-operate-tab`))
    }
  }, [c.caseid, c.operate])
  return (
    <div className={style.container}>
      <div className={style.operate}>
        <div className={style.header}>
          <div className={style['tab-extra']}>
            {renderDropdown(c.caseid, usedOperate, unuseOperate, openedOperateKey, tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft, setActiveKey, setOpenedOperateKey, setUseOperate, setUnuseOperate)}
          </div>
          <div className={tabContainerClass.join(' ')} ref={tabContainerRef}>
            <div className={prevClass.join(' ')} onClick={() => leftClickHandle(tabContainerRef, tabsRef, scrollLeft, isOver, setScrollLeft)}>
              <LeftOutlined />
            </div>
            <div className={nextClass.join(' ')} onClick={() => rightClickHandle(tabContainerRef, tabsRef, scrollLeft, isOver, setScrollLeft)}>
              <RightOutlined />
            </div>
            <div className={style['tab-list']}>
              <div className={style.tabs} ref={tabsRef} style={{ left: `${scrollLeft}px` }}>
                {usedOperate.map((li, i) => {
                  const isActive = li.key === activeKey
                  return (
                    <Tab
                      ref={isActive ? activeTabRef : null}
                      key={li.key}
                      title={li.title}
                      active={isActive}
                      onClick={() => selectActiveKey(li.key, usedOperate, unuseOperate, openedOperateKey, tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft, setActiveKey, setOpenedOperateKey, setUseOperate, setUnuseOperate)}
                      closeHandle={() => closeTagHandle(i, c.caseid, usedOperate, unuseOperate, activeKey, openedOperateKey, tabContainerRef, tabsRef, activeTabRef, scrollLeft, setIsOver, setScrollLeft, setActiveKey, setOpenedOperateKey, setUseOperate, setUnuseOperate)}
                    />
                  )
                })}
              </div>
            </div>
          </div>
        </div>
      </div>
      {renderContent(usedOperate, activeKey, openedOperateKey)}
    </div>
  )
}

export default Main
